﻿using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WorldConqueror.Libraries.MVCExtensions.Helpers;

namespace WorldConqueror.Libraries.MVCExtensions.ModelBinders
{
    public class InterfaceModelBinder : IModelBinder
    {

        private IModelBinder DefaultModelBinder {get;set;}
        private IMethodInfoHelper MethodInfoHelper { get; set; }
        private IGenericFactory ModelFactory { get; set; }
        private IControllerContextWrapper ControllerContextWrapper { get; set; }
        private IModelBindingContextWrapper ModelBindingContextWrapper { get; set; }

        public InterfaceModelBinder(
            IModelBinder defaultModelBinder,
            IMethodInfoHelper methodInfoHelper, 
            IGenericFactory modelFactory,
            IControllerContextWrapper controllerContextWrapper,
            IModelBindingContextWrapper modelBindingContextWrapper)
        {
            DefaultModelBinder = defaultModelBinder;
            MethodInfoHelper = methodInfoHelper;
            ModelFactory = modelFactory;
            ControllerContextWrapper = controllerContextWrapper;
            ModelBindingContextWrapper = modelBindingContextWrapper;
        }

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            ControllerContextWrapper.ControllerContext = controllerContext;
            ModelBindingContextWrapper.ModelBindingContext = bindingContext;

            return BindModel();
        }

        public virtual object BindModel()
        {

            if (ModelBindingContextWrapper.ModelType.IsInterface)
            {
                var methodName = MethodInfoHelper.GetMethodName(() => ModelFactory.CreateInstance<IGenericFactory>());

                var modelInstance = ModelFactory.GetType().GetMethod(methodName)
                        .MakeGenericMethod(ModelBindingContextWrapper.ModelType).Invoke(ModelFactory, null);

                Func<object> modelAccessor = () => modelInstance;

                ModelBindingContextWrapper.ModelBindingContext.ModelMetadata = new ModelMetadata(
                    new DataAnnotationsModelMetadataProvider(),
                    ModelBindingContextWrapper.ModelBindingContext.ModelMetadata.ContainerType,
                    modelAccessor,
                    modelInstance.GetType(),
                    ModelBindingContextWrapper.ModelBindingContext.ModelName);
                
            }

            return DefaultModelBinder.BindModel(
                    ControllerContextWrapper.ControllerContext,
                    ModelBindingContextWrapper.ModelBindingContext);
        }        

    }
}